//
//  UIScrollView+Refresh.m
//  SHDoctor
//
//  Created by Mac mini on 15/10/10.
//  Copyright © 2015年 ShiHeng. All rights reserved.
//

#import "UIScrollView+Refresh.h"

#import <objc/runtime.h>

static CGFloat MaxOffsetY = 60.0f;

static NSString* KVO_ContentOffset = @"contentOffset";
static NSString* KVO_ContentSize = @"contentSize";

@implementation UIScrollView(Refresh)

+ (void)load {
    
    Method dealloc = class_getInstanceMethod([self class], NSSelectorFromString(@"dealloc"));
    Method refresh_dealloc = class_getInstanceMethod([self class], @selector(refresh_dealloc));
    method_exchangeImplementations(dealloc, refresh_dealloc);
}

- (void)refresh_dealloc {
    
    [self refresh_dealloc];
}

#pragma mark -
#pragma mark - KVO methods

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    
    if ([keyPath isEqualToString: KVO_ContentOffset]) {
        
        id<UIScrollViewRefreshDelegate> refreshDelgate = self.refreshDelegate;
        
        if (refreshDelgate == nil) {
            return;
        }
        
        if (![self isDragging] && UIEdgeInsetsEqualToEdgeInsets(self.contentInset, [self settingInset])) {
            
            if (![refreshDelgate respondsToSelector: @selector(scrollViewWillRefreshWithDirection:)] || ![refreshDelgate respondsToSelector: @selector(scrollViewDidRefreshWithDirection:)]) {
                return;
            }
            
            NSValue* newPointValue = [change valueForKey: NSKeyValueChangeNewKey];
            CGFloat offsetY = [newPointValue CGPointValue].y;
            
            if (offsetY < -(MaxOffsetY + self.settingInset.top)) {
                
                BOOL refresh = [refreshDelgate scrollViewWillRefreshWithDirection: RefreshDirectionIsReload];
                if (!refresh) {
                    return;
                }
                [self setContentInset: UIEdgeInsetsMake(MaxOffsetY + self.settingInset.top, 0, 0, 0)];
                [self.headerView startLoading];
                
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [refreshDelgate scrollViewDidRefreshWithDirection: RefreshDirectionIsReload];
                });
            }
            else if (offsetY > (self.contentSize.height - CGRectGetHeight(self.bounds) + MaxOffsetY) && self.contentSize.height > CGRectGetHeight(self.bounds)) {
                
                if ([self.footerView isLoading]) {
                    return;
                }
                
                BOOL refresh = [refreshDelgate scrollViewWillRefreshWithDirection: RefreshDirectionIsLoadMore];
                if (!refresh) {
                    return;
                }
                
                [self setContentInset: UIEdgeInsetsMake(self.settingInset.top, 0, MaxOffsetY, 0)];
                
                [self.footerView startLoading];
                
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [refreshDelgate scrollViewDidRefreshWithDirection: RefreshDirectionIsLoadMore];
                });
            }
        }
    }
    else if ([keyPath isEqualToString: KVO_ContentSize]) {
        
        NSValue* contentSize = [change valueForKey: NSKeyValueChangeNewKey];
        CGFloat height = [contentSize CGSizeValue].height;
        
        self.footerView.hidden = height > CGRectGetHeight(self.bounds) ? NO : YES;
        
        [self.footerView setCenter: CGPointMake(CGRectGetWidth(self.footerView.bounds)/2, height + CGRectGetHeight(self.footerView.bounds)/2)];
    }
}

#pragma mark - Setter methods

@dynamic refreshDelegate;

static const void *UIScrollViewRefreshDelegateValue = &UIScrollViewRefreshDelegateValue;

- (id<UIScrollViewRefreshDelegate>)refreshDelegate {
    
    return objc_getAssociatedObject(self, UIScrollViewRefreshDelegateValue);
}

- (void)setRefreshDelegate:(id<UIScrollViewRefreshDelegate>)refreshDelegate {
    
    id<UIScrollViewRefreshDelegate> scrollViewRefreshDelegate = [self refreshDelegate];
    
    if (scrollViewRefreshDelegate == nil && refreshDelegate != nil) {
        
        [self addObserver: self forKeyPath: KVO_ContentOffset options: NSKeyValueObservingOptionNew context: nil];
        [self addObserver: self forKeyPath: KVO_ContentSize options: NSKeyValueObservingOptionNew context: nil];
        
        [self initHeaderView];
        [self initFooterView];
    }
    else if (scrollViewRefreshDelegate && refreshDelegate == nil) {
        
        [self removeObserver: self forKeyPath: KVO_ContentOffset];
        [self removeObserver: self forKeyPath: KVO_ContentSize];
        
        [self cleanAllSubViews];
    }
    
    objc_setAssociatedObject(self, UIScrollViewRefreshDelegateValue, refreshDelegate, OBJC_ASSOCIATION_ASSIGN);
}


@dynamic settingInset;

static const void *UIScrollViewRefreshSettingInsetValue = &UIScrollViewRefreshSettingInsetValue;

- (UIEdgeInsets)settingInset {
    
    id value = objc_getAssociatedObject(self, UIScrollViewRefreshSettingInsetValue);
    return value == nil ? UIEdgeInsetsZero : [value UIEdgeInsetsValue];
}

- (void)setSettingInset:(UIEdgeInsets)settingInset {
    
    [self setContentInset: settingInset];
    objc_setAssociatedObject(self, UIScrollViewRefreshSettingInsetValue, [NSValue valueWithUIEdgeInsets: settingInset], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}


@dynamic headerView;

static const void *UIScrollViewRefreshHeaderViewValue = &UIScrollViewRefreshHeaderViewValue;

- (UIScrollViewRefreshHeaderView *)headerView {
    
    return objc_getAssociatedObject(self, UIScrollViewRefreshHeaderViewValue);
}

- (void)setHeaderView:(UIScrollViewRefreshHeaderView *)headerView {
    
    objc_setAssociatedObject(self, UIScrollViewRefreshHeaderViewValue, headerView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}


@dynamic footerView;

static const void *UIScrollViewRefreshFooterViewValue = &UIScrollViewRefreshFooterViewValue;

- (UIScrollViewRefreshFooterView *)footerView {
    
    return objc_getAssociatedObject(self, UIScrollViewRefreshFooterViewValue);
}

- (void)setFooterView:(UIScrollViewRefreshFooterView *)footerView {
    
    objc_setAssociatedObject(self, UIScrollViewRefreshFooterViewValue, footerView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

#pragma mark -
#pragma mark - Public methods
- (void)reloadRefreshData {
    
    [self.headerView stopLoading];
    [self.footerView stopLoading];
    
    if (!UIEdgeInsetsEqualToEdgeInsets(self.contentInset, [self settingInset])) {
        
        [UIView animateWithDuration: 0.25 animations:^{
            [self setContentInset: [self settingInset]];
        }completion:^(BOOL finished) {
            if ([self respondsToSelector: @selector(reloadData)]) {
                [self reloadData];
            }
        }];
    }
    else {
        if ([self respondsToSelector: @selector(reloadData)]) {
            [self reloadData];
        }
    }
}

#pragma mark - Private methods

- (void)reloadData {
    //  次类不实现功能,让子类去完成对应的操作
}

- (void)initHeaderView {
    
    UIScrollViewRefreshHeaderView *headerView = [UIScrollViewRefreshHeaderView createView];
    headerView.center = CGPointMake(CGRectGetWidth(headerView.bounds)/2, -CGRectGetHeight(headerView.bounds)/2);

    [self addSubview: headerView];
    
    [self setHeaderView: headerView];
}

- (void)initFooterView {
    
    UIScrollViewRefreshFooterView *footerView = [UIScrollViewRefreshFooterView createView];
    
    CGFloat height = self.contentSize.height;
    
    footerView.hidden = height > CGRectGetHeight(self.bounds) ? NO : YES;
    [footerView setCenter: CGPointMake(CGRectGetWidth(footerView.bounds)/2, height + CGRectGetHeight(footerView.bounds)/2)];
    
    [self addSubview: footerView];
    
    footerView.titleLabel.text = @"推荐更多中...";
    footerView.lastLoadingTime.hidden = true;
    
    [self setFooterView: footerView];
}

- (void)cleanAllSubViews {
    
    [self.headerView removeFromSuperview];
    [self.footerView removeFromSuperview];
}

@end


@implementation UIScrollViewRefreshView

#pragma mark - Public methods

+ (instancetype)createView {
    
    UIScrollViewRefreshView *refreshView = [[UIScrollViewRefreshView alloc] initWithFrame: CGRectMake(0, 0, CGRectGetWidth([[UIScreen mainScreen] bounds]), 60)];
    
    UILabel *titleLabel = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, CGRectGetWidth(refreshView.bounds), 20)];
    titleLabel.backgroundColor = [UIColor clearColor];
    titleLabel.textColor = [UIColor darkGrayColor];
    titleLabel.textAlignment = NSTextAlignmentCenter;
    titleLabel.font = [UIFont systemFontOfSize: 13];
    titleLabel.text = @"正在加载中...";
    titleLabel.center = CGPointMake(CGRectGetWidth(refreshView.bounds)/2 + 20, CGRectGetHeight(refreshView.bounds)/2 - 5);
    [refreshView addSubview: titleLabel];
    refreshView.titleLabel = titleLabel;
    
    UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray];
    activity.center = CGPointMake(CGRectGetWidth(refreshView.bounds)/2 - 35, CGRectGetHeight(refreshView.bounds)/2 - 5);
    activity.hidesWhenStopped = NO;
    [refreshView addSubview: activity];
    refreshView.loadingActivity = activity;
    
    UILabel *updateLabel = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, CGRectGetWidth(refreshView.bounds), 20)];
    updateLabel.backgroundColor = [UIColor clearColor];
    updateLabel.textColor = [UIColor lightGrayColor];
    updateLabel.font = [UIFont systemFontOfSize: 13];
    updateLabel.textAlignment = NSTextAlignmentCenter;
    updateLabel.center = CGPointMake(CGRectGetWidth(refreshView.bounds)/2, CGRectGetHeight(refreshView.bounds)/2 + 15);
    [refreshView addSubview: updateLabel];
    refreshView.lastLoadingTime = updateLabel;
    
    [refreshView updateLoadingTime];
    
    return refreshView;
}

- (void)startLoading {
    
    _isLoading = true;
    
    [_loadingActivity startAnimating];
}

- (void)stopLoading {
    
    _isLoading = false;
    
    [_loadingActivity stopAnimating];
}

#pragma mark - Private methods

- (void)updateLoadingTime {
    
    self.lastLoadingTime.text = [NSString stringWithFormat: @"最后更新于:%@", [self getCurrentTime]];
}

- (NSString*)getCurrentTime {
    
    static NSDateFormatter *dateFormatter = nil;
    
    if (dateFormatter == nil) {
        
        dateFormatter = [NSDateFormatter new];
        [dateFormatter setDateFormat: @"yyyy-MM-dd HH:mm"];
    }
    
    return [dateFormatter stringFromDate: [NSDate date]];
}

@end


@implementation UIScrollViewRefreshHeaderView


@end


@implementation UIScrollViewRefreshFooterView


@end